package org.example.common.sms.impl;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.example.common.sms.SmsReportBean;
import org.example.common.sms.SmsService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Service
@Slf4j
public class KFSmsServiceImpl implements SmsService {

    @Value("${sms.company-id}")
    private String companyId;

    @Value("${sms.app-id}")
    private String appId;

    @Value("${sms.key}")
    private String key;

    @Value("${sms.code-template-id}")
    private String verifyCodeTemplateId;

    private static final String VERSION = "1.2.0";
    private static final String SIGN_TYPE = "MD5";
    private static final String URL_TEMPLATE_SEND = "https://apis.shlianlu.com/sms/trade/template/send";

    @Override
    public boolean sendSms(List<String> mobiles, String content) {
        log.warn("普通短信未实现，建议统一使用模板短信");
        return false;
    }

    @Override
    public boolean sendSms(List<String> mobiles, String templateID, List<String> params) {
        try {
            if (templateID == null || templateID.isEmpty()) {
                templateID = verifyCodeTemplateId;
            }
            JSONObject req = new JSONObject();
            req.set("AppId", appId);
            req.set("MchId", companyId);
            req.set("Version", VERSION);
            req.set("SignType", SIGN_TYPE);
            req.set("Type", "3");
            req.set("PhoneNumberSet", mobiles);
            req.set("TemplateId", templateID);
            req.set("TemplateParamSet", params);
            req.set("TimeStamp", String.valueOf(System.currentTimeMillis()));

            String sign = md5Sign(req);
            req.set("Signature", sign);

            String body = req.toString();
            HttpResponse resp = HttpRequest.post(URL_TEMPLATE_SEND)
                    .header("Accept", "application/json")
                    .header("Content-Type", "application/json;charset=utf-8")
                    .body(body)
                    .execute();

            if (resp == null || resp.body() == null) {
                log.error("短信发送响应为空");
                return false;
            }
            String respBody = resp.body();
            var obj = JSONUtil.parseObj(respBody);
            String status = obj.getStr("status");
            boolean ok = "00".equals(status);
            if (!ok) {
                log.error("短信发送失败 status={}, body={}", status, respBody);
            }
            return ok;
        } catch (Exception e) {
            log.error("短信发送异常", e);
            return false;
        }
    }

    @Override
    public List<SmsReportBean> checkSmsSendStatus(String taskID, Integer pageNo, Integer pageSize) {
        log.warn("短信报告查询未实现，按需补充");
        return List.of();
    }

    @Override
    public boolean checkSmsChannelConfiguration() {
        return companyId != null && appId != null && key != null;
    }

    private String md5Sign(JSONObject json) throws Exception {
        // 按联麓文档：签名参与字段需排除以下字段及为空的项
        Set<String> excluded = Set.of(
                "Signature",
                "SessionContext",
                "PhoneNumberSet",
                "SessionContextSet",
                "ContextParamSet",
                "TemplateParamSet",
                "PhoneList",
                "phoneSet"
        );
        Map<String, Object> map = JSONUtil.parseObj(json);
        String joined = map.entrySet().stream()
                .filter(e -> !excluded.contains(e.getKey()))
                .filter(e -> e.getValue() != null && !e.getValue().toString().isEmpty())
                .sorted(Map.Entry.comparingByKey())
                .map(e -> e.getKey() + "=" + e.getValue())
                .collect(Collectors.joining("&")) + "&key=" + URLEncoder.encode(key, StandardCharsets.UTF_8.name());
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] digest = md.digest(joined.getBytes());
        StringBuilder sb = new StringBuilder();
        for (byte b : digest) sb.append(String.format("%02x", b & 0xff));
        return sb.toString().toUpperCase();
    }
}
